﻿using System;
using System.Collections.Generic;
using System.Linq;

using Whoever.Patterns.Data;
using Whoever.Framework.Struct;
using Whoever.Framework.Base;
using Whoever.Framework.Attributes;

namespace Whoever.Patterns.Business
{
    public abstract class Manager<TEntity> : IDisposable, IManager<TEntity> where TEntity : BusinessEntity, new()
    {
        private readonly Repository<TEntity> _repository;

        protected Repository<TEntity> Repository
        {
            get
            {
                return _repository;
            }
        }

        public Manager(Repository<TEntity> repository)
        {
            _repository = repository;
        }

        public virtual TEntity GetById(TEntity entity)
        {
            return _repository.GetById(entity);
        }

        public virtual TEntity GetByKeys(ViewModel<TEntity> model)
        {
            return _repository.GetByKeys(model);
        }

        public virtual TEntity GetByKeys(TEntity entity)
        {
            return _repository.GetByKeys(entity);
        }

        public virtual IEnumerable<TEntity> GetAll(ref Pager pager)
        {
            return _repository.GetAll(ref pager);
        }

        public virtual IEnumerable<TEntity> GetAll()
        {
            return _repository.GetAll();
        }

        public virtual IEnumerable<TEntity> GetAllRelated(ref Pager pager)
        {
            return _repository.GetAllRelated(ref pager);
        }

        public virtual IEnumerable<TEntity> GetAllRelated()
        {
            return _repository.GetAllRelated();
        }

        public virtual IEnumerable<TEntity> GetJustRelated()
        {
            return _repository.GetJustRelated();
        }

        public virtual IEnumerable<TEntity> GetFiltered(TEntity entity)
        {
            return _repository.GetFiltered(entity);
        }

        public virtual IEnumerable<TEntity> GetFiltered(TEntity entity, ref Pager pager)
        {
            return _repository.GetFiltered(entity, ref pager);
        }

        public virtual IEnumerable<TEntity> GetFiltered(ViewModel<TEntity> model)
        {
            return _repository.GetFiltered(model);
        }

        public virtual IEnumerable<TEntity> GetFiltered(ViewModel<TEntity> model, ref Pager pager)
        {
            return _repository.GetFiltered(model, ref pager);
        }

        public virtual IEnumerable<TEntity> GetFiltered(Filter filter)
        {
            return _repository.GetFiltered(filter);
        }

        public virtual IEnumerable<TEntity> GetFiltered(Filter filter, ref Pager pager)
        {
            return _repository.GetFiltered(filter, ref pager);
        }

        public virtual IEnumerable<TEntity> GetFilteredRelated(ViewModel<TEntity> model)
        {
            return _repository.GetFilteredRelated(model);
        }

        public virtual IEnumerable<TEntity> GetFilteredRelated(ViewModel<TEntity> model, ref Pager pager)
        {
            return _repository.GetFilteredRelated(model, ref pager);
        }

        public void FillSelectablesRelations(ViewModel<TEntity> model)
        {
            foreach (var property in model.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(SelectableRelationship), true).Length != 0))
            {
                var setterMethod = property.GetSetMethod();
                SelectableRelationship attribute = property.GetCustomAttributes(typeof(SelectableRelationship), true).First() as SelectableRelationship;
                var manager = Activator.CreateInstance(attribute.ManagerType);
                var getAllMethod = manager.GetType().GetMethods().Where(m => m.Name == "GetAll").Last();
                setterMethod.Invoke(model, new object[] { getAllMethod.Invoke(manager, new object[] { }) });
            }
        }

        public virtual void Insert(IEnumerable<TEntity> items)
        {
            _repository.Insert(items);
        }

        public virtual int Insert(TEntity item)
        {
            return _repository.Insert(item);
        }

        public virtual void Update(IEnumerable<TEntity> items)
        {
            _repository.Update(items);
        }

        public virtual void Update(TEntity item)
        {
            _repository.Update(item);
        }

        public virtual void Delete(IEnumerable<TEntity> items)
        {
            _repository.Delete(items);
        }

        public virtual void Delete(TEntity item)
        {
            _repository.Delete(item);
        }

        public void RollBack()
        {
            _repository.RollBack();
        }

        public void UndoChanges(TEntity item)
        {
            _repository.UndoChanges(item);
        }

        public void UndoChanges(IEnumerable<TEntity> items)
        {
            _repository.UndoChanges(items);
        }

        public virtual void Dispose()
        {
            throw new NotImplementedException();
        }
    }
}
